/**
 * Elite WebSocket CTIProxy Client
 * Created by Jeff on 2016/11/02.
 */
define([$E.softphoneBasePath + "/softphone/softphone.constants" + $E.jsv], function($CTI_CONST){
    function commonreplace(template, args) {
        if (arguments.length > 1 && typeof arguments[0] === "string") {
            var result = arguments[0];
            if (arguments.length == 2 && typeof arguments[1] === "object") {
                var obj = arguments[1];
                for (var key in obj) {
                    if (obj[key] != undefined) {
                        var reg = new RegExp("({" + key + "})", "g");
                        result = result.replace(reg, obj[key]);
                    }
                }
            } else {
                for (var i = 1, len = arguments.length; i < len; i++) {
                    if (arguments[i] != undefined) {
                        // 这个在索引大于9时会有问题
                        // var reg = new RegExp("({[" + (i - 1) + "]})", "g");
                        var reg = new RegExp("({)" + (i - 1) + "(})", "g");
                        result = result.replace(reg, arguments[i]);
                    }
                }
            }
            return result;
        } else {
            return arguments[0];
        }
    }
    
    var ELITEWSCTIClient={
			createNew:function(){
				var softphone={};
				softphone.ctirefid = 0;
				softphone.rqqueue = {};
				softphone.dn = "";
				softphone.registreddn = "";
				softphone.agentid = "";
				softphone.agentpassword = "";
				softphone.agentgroup = "";

				m_Calllist = {};
				//CompleteTransferWhenDialing, CompleteTransferWhenNR, CompleteTransferWhenRB, CompleteTransferWhenEstablish, and same for CompleteConference
				f_autocomplete = "";
				conn_autocomplete = "";
				
				var keyvaluesplit = "=";
				
			    var Error = function (error, args) {
			        return this.init(error, args);
			    };
			    Error.UNKNOW_ERROR = {
		            code: 80000,
		            name: "UNKNOW_ERROR",
		            message: "未知错误"
		        };
			    Error.INVOKE_TIMEOUT = {
			        code: 80100,
			        name: "INVOKE_TIMEOUT",
			        message: "请求超时 - {method}"
			    };
			    Error.REQUEST_FAIL_CTIMSG = {
			    	code: 80101,
			    	name: "REQUEST_FAIL_CTIMSG",
			    	message: "请求失败 - {method}，失败代码：{errorcode}",
			    	data: "{data}"
			    }
			    Error.NO_DEVICE_INFO = {
			        code: 80110,
			        name: "NO_DEVICE_INFO",
			        message: "未获取到分机信息"
			    };
			    Error.INVALID_DEVICE_ID = {
			        code: 80111,
			        name: "INVALID_DEVICE_ID",
			        message: "无效的分机号：{deviceId}"
			    };
			    Error.EXIST_DEVICE_LOGIN = {
			        code: 80112,
			        name: "EXIST_DEVICE_LOGIN",
			        message: "分机已登录，登录工号：{agentId}",
			    };
			    Error.RESOURCE_BUSY = {
			        code: 80113,
			        name: "RESOURCE_BUSY",
			        message: "分机正在通话"
			    };

			    Error.INVALID_AGENT_ID = {
			        code: 80121,
			        name: "INVALID_AGENT_ID",
			        message: "无效的工号：{agentId}"
			    };
			    Error.INVALID_PASSWORD = {
		            code: 80122,
		            name: "INVALID_PASSWORD",
		            message: "无效的密码"
		        };
			    Error.EXIST_AGENT_LOGIN = {
			        code: 80123,
			        name: "EXIST_AGENT_LOGIN",
			        message: "工号已登录，登录分机：{deviceId}"
			    };
			    Error.INVALID_STATE_ERR = {
			    	code: 80201,
			    	name: "INVALID_STATE_ERR",
			    	message: "无法完成此操"
			    }
			    Error.prototype = {
		            constructor: Error,
		            init: function (error, args) {
		                var newError = null;
		                if (typeof error === "object") {
		                    if (typeof args != undefined) {
		                        newError = Object.create(error);
		                        for (var name in newError) {
		                            newError[name] = commonreplace(newError[name], args);
		                        }
		                    } else {
		                        newError = error;
		                    }
		                } else if (typeof error === "string") {
		                    newError = {
		                        code: 80999,
		                        name: "Error",
		                        message: error
		                    };
		                }
		                return newError;
		            }
		        };

				softphone.connectserver = function(serverendpoint, onOpen,onClose,onMessage,onError,onSendMessage){
					try {
						softphone.websocket = new WebSocket(serverendpoint);
						console.log('_softphone: websocket init: ' + softphone.websocket.url);
						softphone.websocket.onopen = function(evt){
							softphone.registereddn = '';
							onOpen(evt);
						}
						softphone.websocket.onclose = function(evt){
							softphone.registereddn = '';
							console.log('_softphone: websocket closed');
							onClose(evt);
						}
						softphone.websocket.onmessage = function(evt){
							_onmessage(evt);
							//$SC.onCTIEvent(evt);
							//onMessage.apply(this, arguments);
							if (evt.data2) {
								if (evt.data2.internaluse) {
									
								} else {
									onMessage(evt.data2);
								}
							} else {
								onMessage(evt);
							}
						}
						softphone.websocket.onerror = function(evt){
							onError(evt);
						}
						
						softphone.onMessage = onMessage;
						
						softphone.OnSendMessage = function(evt){
							onSendMessage(evt);
						}
						keyvaluesplit = $SC.getConfig('CTI', 'KeyValueSplit');
					} catch (err) {
						debugger;
						softphone.logmsg('connectserver error: code = ' + err.code + ', message = ' + err.message);
					}
				};
				
				//REQ_INITIALIZEADS = 80,
				//REQ_OPENSERVER = 81,
				//REQ_REGISTERAGENT = 83,
				//REQ_UNREGISTERADDRESS = 88,
		        //REQ_SINGLESTEPTRANSFER = 100,
		        //REQ_SINGLESTEPCONFERENCE = 101,
		        //REQ_CLOSESERVER = 102,
		        //REQ_SWAPHOLD = 103,
		        //REQ_STARTRECORD = 104,
		        //REQ_STOPRECORD = 105,
		        //REQ_SETOHHOOK = 106,
		        //REQ_REPORTAGENTID = 107,
		        //REQ_STARTPLAY = 108,
		        //REQ_STOPPLAY = 109,
		        //REQ_MUTE = 110,
		        //REQ_UNMUTE = 111,
		        //REQ_INTERCEPT = 112,
		        //REQ_FORCEHANGUP = 113,
		        //REQ_FORCEDISCONNECTAGENTBYDN = 114,
		        //REQ_SENDDTMF = 115,
		        //REQ_LISTEN = 116,
		        //REQ_BARGEIN = 117,
		        //REQ_GETCURRENTAGENT = 118,
		        //REQ_GETCURRENTAGENTSTATE = 119,
		        //REQ_GETQUEUEINFO = 120,
		        //REQ_DEFLECTCALL = 121,
		        //REQ_SETNIGHTRING = 122,
		        //REQ_ESCAPESERVICE = 123,
		        //REQ_GETDTMF = 124,
		        //REQ_SENDIVRMESSAGE = 125,
		        //REQ_FORCEAGENT = 126,
		        //REQ_FORCEAGENTREADY = 127,
		        //REQ_FORCEAGENTLOGOUT = 128,
		        //REQ_PLAYTTS = 129,
		        //REQ_FORCETAKEOVER = 130,
		        //REQ_TRANSFERTOIVRANDWAITBACK = 131,
		        //REQ_APCPLAYFASTFORWARD = 132,
		        //REQ_APCPLAYFASTBACKWARD = 133,
		        //REQ_QUERYAGENTSTATE = 134,
		        //REQ_QUERYAGENTGROUPSTATE = 135,
		        //REQ_COMMONCALL = 136,
		        //REQ_WRAPUPENDED = 137,
		        //REQ_COACH = 138,
		        //REQ_FORWARDCALL = 139,
		        //REQ_SNAPSHOTDEVICE = 140,
		        //REQ_SNAPSHOTCALL = 141,
		        //REQ_RESETAGENTSKILL = 142,
				//REQ_DELETEPARTY = 143, 
			    //REQ_MAX = 144
			    
				//REQ_REGISTERADDRESS = 82
				softphone.registerdn = function(dn)
			    {
					if (softphone.registereddn && softphone.registereddn != dn) {
						unregisterdn(softphone.registereddn);
					}
			    	this.dn = dn;
			    	//var request = '{"request":{"type":1,"value":"82"},"regmode":{"type":1,"value":"1"},"dn":{"type":3,"value":"'+dn+'"},"token":{"type":3,"value":"'+$E.getActiveProject().token+'"},"ds":{"type":3,"value":"'+$E.dataService.key+'"}}';
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	softphone.websocketsend({
			    		request: {type: 1, value: 82},
			    		regmode: {type: 1, value: 1},
			    		dn: {type: 3, value: dn},
			    		token: {type: 3, value: $E.getActiveProject().token},
			    		ds: {type: 3, value: $E.dataService.key}
			    	}, 'registerdn', {timeout: 5000, succevents: [16]});
			    };
			    softphone.unregisterdn = function(dn)
			    {
			    	softphone.websocketsend({
			    		request: {type: 1, value: 88},
			    		dn: {type: 3, value: dn}
			    	})
			    }
			    //REQ_SETAGENTLOGIN = 84
			    softphone.login = function(agentid,dn,agentpassword,agentgroup,workmode,acdagent)
			    {
					//this.getcurrentagent('8005', '5005');
					//this.getcurrentagent('8005', '15005');

			    	this.agentid = agentid;
			    	this.dn = dn;
			    	this.agentpassword = agentpassword;
			    	this.agentgroup = agentgroup;
			    	//var request = '{"request":{"type":1,"value":"84"},"agentid":{"type":3,"value":"'+agentid+'"},"password":{"type":3,"value":"'+agentpassword+'"},"agentgroup":{"type":3,"value":"'+agentgroup+'"},"dn":{"type":3,"value":"'+dn+'"},"acdagent":{"type":1,"value":"'+acdagent+'"},"workmode":{"type":1,"value":"'+workmode+'"}}';
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	softphone.snapshotdevice(dn, {timeout: 5000, internaluse: true})
		            .then(function(e) {
		                debugger;
		            	if (e.callcount && e.callcount.value > 0) {
			    			err = new Error(Error.RESOURCE_BUSY);
			    			softphone.InternalOnError(err.message, err.code, err.name);
			    			return;
		            	}
		            	softphone.getcurrentagent(dn, agentid, {timeout: 5000, internaluse: true})
		            	.then(function(e) {
		            		debugger;
		            		if (e.otherdn && e.otherdn.value && e.otherdn.value != dn) {
		            			err = new Error(Error.EXIST_AGENT_LOGIN, {deviceId: e.otherdn.value});
		            			softphone.InternalOnError(err.message, err.code, err.name);
		            			return;
		            		}
		            		softphone.getcurrentagent(dn, undefined, {timeout: 5000, internaluse: true})
		            		.then (function(e) {
		            			debugger;
		            			if (e.agentid) {
		            				if (e.agentid.value && e.agentid.value != agentid) {
				            			err = new Error(Error.EXIST_DEVICE_LOGIN, {agentId: e.agentid.value});
				            			softphone.InternalOnError(err.message, err.code, err.name);
				            			return;
		            				} else if (e.agentid.value == agentid){
		            					debugger;
		            			    	softphone.agentlogout(agentid, agentgroup, dn, {timeout: 5000, internaluse: true, succevents: [71]})
		            			    	.then (function(e) {
		            			    		softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);	            			    		
		            			    	}, function(e) {
		            			    		softphone.onMessage(e);
		            			    	});
		            			    } else {
		            			    	softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);
		            				}
		            			} else {
			    			    	softphone.agentlogin(agentid, dn, agentpassword, agentgroup, workmode, acdagent);
		            			}
		            		}, function(e) {
		            			softphone.onMessage(e);
		            		});
		            	}, function(e) {
		            		debugger;
		            		var datas = JSON.parse(e.data);
		            		var errcode;
		            		if (datas && datas.errorcode) {
		            			errcode = datas.errorcode.value;
		            		}
		            		if (errcode == 3 || errcode == 12) {
		            			err = new Error(Error.INVALID_AGENT_ID, {agentId: agentid});
		            			softphone.InternalOnError(err.message, err.code, err.name);
		            			return;
		            		} else {
		            			softphone.InternalOnError(e.message, e.code, e.name);
		            		}
		            	})
		            }, function(e) {
            			softphone.InternalOnError(e.message, e.code, e.name);
		            });
			    	
			    	//softphone.queryagentstate(dn, agentid, 1);
			    	//softphone.getcurrentagent(dn);
			    	/*
			    	*/
			    }
			    
			    softphone.agentlogin = function(agentid, dn, agentpassword, agentgroup, workmode, acdagent, options) {
			    	return softphone.websocketsend({
			    		request: {type: 1, value: 84},
			    		agentid: {type: 3, value: agentid},
			    		password: {type: 3, value: agentpassword},
			    		agentgroup: {type: 3, value: agentgroup},
			    		dn: {type: 3, value: dn},
			    		acdagent: {type: 1, value: acdagent},
			    		workmode: {type: 1, value: workmode}
			    	}, 'login', options);
			    }
			    
			    //REQ_SETAGENTLOGOUT = 87
			    softphone.agentlogout = function(agentid, agentgroup, dn, options){
			    	//var request='{"request":{"type":1,"value":"87"},"agentid":{"type":3,"value":"'+this.agentid+'"},"agentgroup":{"type":3,"value":"'+this.agentgroup+'"},"dn":{"type":3,"value":"'+this.dn+'"}}';
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	if (!agentid) {
			    		agentid = this.agentid;
			    	}
			    	if (!agentgroup) {
			    		agentgroup = this.agentgroup;
			    	}
			    	if (!dn) {
			    		dn = this.dn;
			    	}
			    	return softphone.websocketsend({
			    		request: {type: 1, value: 87},
			    		agentid: {type: 3, value: agentid},
			    		agentgroup: {type: 3, value: agentgroup},
			    		dn: {type: 3, value: dn}
			    	}, 'agentlogout', options);
			    }
			    //REQ_SETAGENTNOTREADY = 86
			    softphone.agentnotready = function(workmode)
			    {
			    	//var request='{"request":{"type":1,"value":"86"},"dn":{"type":3,"value":"'+this.dn+'"},"workmode":{"type":1,"value":"'+"3"+'"},"agentid":{"type":3,"value":"'+this.agentid+'"},"password":{"type":3,"value":"'+this.agentpassword+'"},"agentgroup":{"type":3,"value":"'+this.agentgroup+'"}}';
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	if (workmode == 4) {
			    		return softphone.acw();
			    	}
			    	softphone.websocketsend({
			    		request: {type: 1, value: 86},
			    		dn: {type: 3, value: this.dn},
			    		workmode: {type: 1, value: 3},
			    		agentid: {type: 3, value: this.agentid},
			    		password: {type: 3, value: this.agentpassword},
			    		agentgroup: {type: 3, value: this.agentgroup}
			    	}, 'agentnotready', {timeout : 5000, succevents: [73]});
			    }
			    softphone.aux = function(reasoncode)
			    {
			    	//var request='{"request":{"type":1,"value":"86"},"dn":{"type":3,"value":"'+this.dn+'"},"workmode":{"type":1,"value":"'+"3"+'"},"reasoncode":{"type":1,"value":"'+reasoncode+'"},"agentid":{"type":3,"value":"'+this.agentid+'"},"password":{"type":3,"value":"'+this.agentpassword+'"},"agentgroup":{"type":3,"value":"'+this.agentgroup+'"}}';
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	softphone.websocketsend({
			    		request: {type: 1, value: 86},
			    		dn: {type: 3, value: this.dn},
			    		workmode: {type: 1, value: 3},
			    		reasoncode: {type: 1, value: reasoncode},
			    		agentid: {type: 3, value: this.agentid},
			    		password: {type: 3, value: this.agentpassword},
			    		agentgroup: {type: 3, value: this.agentgroup}
			    	}, 'aux', {timeout : 5000, succevents: [73]});
			    }
			    softphone.acw = function()
			    {
			    	//var request='{"request":{"type":1,"value":"86"},"dn":{"type":3,"value":"'+this.dn+'"},"workmode":{"type":1,"value":"'+"4"+'"},"agentid":{"type":3,"value":"'+this.agentid+'"},"password":{"type":3,"value":"'+this.agentpassword+'"},"agentgroup":{"type":3,"value":"'+this.agentgroup+'"}}';
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	softphone.websocketsend({
			    		request: {type: 1, value: 86},
			    		dn: {type: 3, value: this.dn},
			    		workmode: {type: 1, value: 4},
			    		agentid: {type: 3, value: this.agentid},
			    		password: {type: 3, value: this.agentpassword},
			    		agentgroup: {type: 3, value: this.agentgroup}
			    	}, 'acw', {timeout : 5000, succevents: [73]});
			    }
			    //REQ_SETAGENTREADY = 85
			    softphone.agentready = function(workmode){
			    	//var request='{"request":{"type":1,"value":"85"},"dn":{"type":3,"value":"'+this.dn+'"},"workmode":{"type":1,"value":"' + (workmode || 0) + '"},"agentid":{"type":3,"value":"'+this.agentid+'"},"password":{"type":3,"value":"'+this.agentpassword+'"},"agentgroup":{"type":3,"value":"'+this.agentgroup+'"}}';
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	softphone.websocketsend({
			    		request: {type: 1, value: 85},
			    		dn: {type: 3, value: this.dn},
			    		workmode: {type: 1, value: workmode || 0},
			    		agentid: {type: 3, value: this.agentid},
			    		password: {type: 3, value: this.agentpassword},
			    		agentgroup: {type: 3, value: this.agentgroup}
			    	}, 'agentready', {timeout : 5000, succevents: [72]});
			    }
		        //REQ_MAKECALL = 90,
			    softphone.makecall = function(dest, userDatas, callback)
			    {
			    	//TODO 可不可以知道这个makecall的结果，如果可以那就可以通过callback传递回去
			    	var requestJSON = {
			    		request: {
			    			type: 1,
			    			value: '90'
			    		},
			    		dn: {
			    			type: 3,
			    			value: this.dn
			    		},
			    		dest: {
			    			type: 3,
			    			value: dest
			    		},
			    		site: {
			    			type: 3,
			    			value: ''
			    		}
			    	};
			    	if (userDatas) {
			    		requestJSON.userdata = {
			    			value: userdata2jsonuserdata(userDatas),
			    			type: 5
			    		}
			    	}
			    	//var request = JSON.stringify(requestJSON);
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	softphone.websocketsend(requestJSON, 'makecall')
			    	//结果，callback？
			    }
		        //REQ_RELEASECALL = 91,
			    softphone.releasecall = function(callid)
			    {
			    	var id="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(id!=""){
				    	//var request='{"request":{"type":1,"value":"91"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+id+'"}}';
				    	//this.websocket.send(request);
				    	//this.OnSendMessage(request);
			    		softphone.websocketsend({
			    			request: {type: 1, value: 91},
			    			dn: {type: 3, value: this.dn},
			    			connectionid: {type: 3, value: id}
			    		}, 'releasecall');
				    } else {
				    	var error = new Error(Error.INVALID_STATE_ERR, {
				    		
				    	});
				    	softphone.InternalOnError(error.message, error.code, error.name);
				    }
			    }

				//REQ_ANSWERCALL = 89,
			    softphone.answercall = function(callid)
			    {
			    	var id="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(id!=""){
				    	//var request='{"request":{"type":1,"value":"89"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+id+'"}}';
				    	//this.websocket.send(request);
				    	//this.OnSendMessage(request);
				    	softphone.websocketsend({
			    			request: {type: 1, value: 89},
			    			dn: {type: 3, value: this.dn},
			    			connectionid : {type: 3, value: id}
			    		}, 'answercall')
				    } else {
				    	var error = new Error(Error.INVALID_STATE_ERR, {
				    		
				    	});
				    	softphone.InternalOnError(error.message, error.code, error.name);
				    }
			    }
			    //REQ_HOLDCALL = 92
			    softphone.holdcall = function(callid)
			    {
			    	var id="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(id!=""){
				    	softphone.websocketsend({
			    			request: {type: 1, value: 92},
			    			dn: {type: 3, value: this.dn},
			    			connectionid : {type: 3, value: id}
			    		}, 'holdcall')
				    } else {
				    	var error = new Error(Error.INVALID_STATE_ERR, {
				    		
				    	});
				    	softphone.InternalOnError(error.message, error.code, error.name);
				    }
			    }
		        //REQ_RETRIEVECALL = 93,
			    softphone.retrievecall = function(callid)
			    {
			    	var id="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(id!=""){
				    	softphone.websocketsend({
			    			request: {type: 1, value: 93},
			    			dn: {type: 3, value: this.dn},
			    			connectionid : {type: 3, value: id}
			    		}, 'retrievecall')
				    } else {
				    	var error = new Error(Error.INVALID_STATE_ERR, {
				    		
				    	});
				    	softphone.InternalOnError(error.message, error.code, error.name);
				    }
			    }
		        //REQ_INITTRANSFER = 94,
			    softphone.inittransfer = function(callid, dest, userdatas)
			    {
			    	var id="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(id!=""){
			    		f_autocomplete = '';
			    		conn_autocomplete = callid;
			    		
				    	var request='{"request":{"type":1,"value":"94"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+id+'"},"dest":{"type":3,"value":"'+dest+'"},"site":{"type":3,"value":""}';
				    	if(userdatas){
				    		userdatas = userdata2jsonuserdata(userdatas);
				    		if (getuserdatabykey(userdatas, 'AutoComplete')){
				    			f_autocomplete = 'completetransferwhendialing';
				    			removeuserdatabykey(userdatas, 'AutoComplete');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenDialing')) {
				    			f_autocomplete = 'completetransferwhendialing';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenDialing');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenNR')) {
				    			f_autocomplete = 'completetransferwhennr';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenNR');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenRB')) {
				    			f_autocomplete = 'completetransferwhenrb';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenRB');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenEstablish')) {
				    			f_autocomplete = 'completetransferwhenestablish';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenEstablish');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenDialing')) {
				    			f_autocomplete = 'completetransferwhendialing';
				    			removeuserdatabykey(userdatas, 'CompleteWhenDialing');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenNR')) {
				    			f_autocomplete = 'completetransferwhennr';
				    			removeuserdatabykey(userdatas, 'CompleteWhenNR');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenRB')) {
				    			f_autocomplete = 'completetransferwhenrb';
				    			removeuserdatabykey(userdatas, 'CompleteWhenRB');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenEstablish')) {
				    			f_autocomplete = 'completetransferwhenestablish';
				    			removeuserdatabykey(userdatas, 'CompleteWhenEstablish');
				    		}
				    		userdatas = checkuudata(userdatas);
				    		if (typeof(userdatas)=='object') {
				    			userdatas = JSON.stringify(userdatas);
				    		}
				    		request+=',"userdata":{"value":'+userdatas+',"type":5}';
				    	}
				    	request+='}';
				    	this.websocket.send(request);
				    	this.OnSendMessage(request);
				    }
			    }
		        //REQ_INITCONFERENCE = 95,
			    softphone.initconference = function(callid, dest, userdatas)
			    {
			    	var id="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(id!=""){
			    		f_autocomplete = '';
			    		conn_autocomplete = callid;

			    		var request='{"request":{"type":1,"value":"95"},"dn":{"type":3,"value":"'+this.dn+'"},"connectionid":{"type":3,"value":"'+id+'"},"dest":{"type":3,"value":"'+dest+'"},"site":{"type":3,"value":""}';
				    	if(userdatas){
				    		userdatas = userdata2jsonuserdata(userdatas);
				    		if (getuserdatabykey(userdatas, 'AutoComplete')){
				    			f_autocomplete = 'completeconferencewhendialing';
				    			removeuserdatabykey(userdatas, 'AutoComplete');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenDialing')) {
				    			f_autocomplete = 'completeconferencewhendialing';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenDialing');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenNR')) {
				    			f_autocomplete = 'completeconferencewhennr';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenNR');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenRB')) {
				    			f_autocomplete = 'completeconferencewhenrb';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenRB');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteConferenceWhenEstablish')) {
				    			f_autocomplete = 'completeconferencewhenestablish';
				    			removeuserdatabykey(userdatas, 'CompleteConferenceWhenEstablish');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenDialing')) {
				    			f_autocomplete = 'completeconferencewhendialing';
				    			removeuserdatabykey(userdatas, 'CompleteWhenDialing');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenNR')) {
				    			f_autocomplete = 'completeconferencewhennr';
				    			removeuserdatabykey(userdatas, 'CompleteWhenNR');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenRB')) {
				    			f_autocomplete = 'completeconferencewhenrb';
				    			removeuserdatabykey(userdatas, 'CompleteWhenRB');
				    		}
				    		if (getuserdatabykey(userdatas, 'CompleteWhenEstablish')) {
				    			f_autocomplete = 'completeconferencewhenestablish';
				    			removeuserdatabykey(userdatas, 'CompleteWhenEstablish');
				    		}
				    		//request+=',"userdata":'+userdatas;
				    		userdatas = checkuudata(userdatas);
				    		if (typeof(userdatas)=='object') {
				    			userdatas = JSON.stringify(userdatas);
				    		}
				    		request+=',"userdata":{"value":'+userdatas+',"type":5}';
				    	}
				    	request+='}';
				    	this.websocket.send(request);
				    	this.OnSendMessage(request);
				    }
			    }
		        //REQ_COMPLETETRANSFER = 96,
			    softphone.completetransfer = function(callid, prevcallid)
			    {
			    	var id="", previd="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(prevcallid){
			    		previd=prevcallid;
			    	}
			    	if(id!=""&&previd!=""){
				    	var request='{"request":{"type":1,"value":"96"},"dn":{"type":3,"value":"'+this.dn+'"},"activecallid":{"type":3,"value":"'+id+'"},"heldcallid":{"type":3,"value":"'+previd+'"}';
				    	request+='}';
				    	this.websocket.send(request);
				    	this.OnSendMessage(request);
				    }
			    }
		        //REQ_COMPLETECONFERENCE = 97,
			    softphone.completeconference = function(callid, prevcallid)
			    {
			    	var id="", previd="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(prevcallid){
			    		previd=prevcallid;
			    	}
			    	if(id!=""&&previd!=""){
				    	//var request='{"request":{"type":1,"value":"97"},"dn":{"type":3,"value":"'+this.dn+'"},"activecallid":{"type":3,"value":"'+id+'"},"heldcallid":{"type":3,"value":"'+previd+'"}';
				    	//request+='}';
				    	//this.websocket.send(request);
				    	//this.OnSendMessage(request);
			    		softphone.websocketsend({
			    			request: {type: 1, value: 97},
			    			dn: {type: 3, value: this.dn},
			    			activecallid: {type: 3, value: id},
			    			heldcallid: {type: 3, value: previd}
			    		}, 'completeconference');
				    } else {
				    	var error = new Error(Error.INVALID_STATE_ERR, {
				    		
				    	});
				    	softphone.InternalOnError(error.message, error.code, error.name);
				    }
			    }
		        //REQ_RECONNECT = 99,
			    softphone.reconnect = function(callid,prevcallid)
			    {
			    	var id="", previd="";
			    	if(callid){
			    		id=callid;
			    	}
			    	if(prevcallid){
			    		previd=prevcallid;
			    	}
			    	if(id!=""&&previd!=""){
				    	var request='{"request":{"type":1,"value":"99"},"dn":{"type":3,"value":"'+this.dn+'"},"activecallid":{"type":3,"value":"'+id+'"},"heldcallid":{"type":3,"value":"'+previd+'"}';
				    	request+='}';
				    	this.websocket.send(request);
				    	this.OnSendMessage(request);
				    } else {
				    	var error = new Error(Error.INVALID_STATE_ERR, {
				    		
				    	});
				    	softphone.InternalOnError(error.message, error.code, error.name);
				    }
			    }
		        ////REQ_MUTETRANSFER = 98,
			    softphone.mutetransfer = function(callid, dest, userdatas)
			    {
/*			    	
			    	if(!userdatas){
				    	userdatas = JSON.stringify({type : 5, value : {}});
				    }
			    	var t_data = JSON.parse(userdatas);
			    	t_data.value.CompleteWhenDialing = {
	    				type : 3,
	    				value : '1'
	    			}
			    	userdatas = JSON.stringify(t_data);
*/					userdatas = userdata2jsonuserdata(userdatas);
			    	userdatas = adduserdata(userdatas, 'CompleteWhenRB', 3, '1')
				    softphone.inittransfer(callid, dest, userdatas);
			    }

			    softphone.keepalive = function(){
			    	var request='{"request":{"type":1,"value":"0"},"dn":{"type":3,"value":"'+this.dn+'"}}';
			    	this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    }
			    
			    softphone.snapshotdevice = function(dn, options) {
			    	//REQ_SNAPSHOTDEVICE = 140,
			    	return softphone.websocketsend({
			    		request: {type: 1, value: 140},
			    		dn: {type: 3, value: dn}
			    	}, 'snapshotdevice', options);
			    }
			    
			    softphone.queryagentstate = function(dn, agentid, otheragent, options) {
			    	//REQ_QUERYAGENTSTATE = 134,
			    	return softphone.websocketsend({
			    		request: {type: 1, value: 134}, 
			    		dn: {type: 3, value: dn}, 
			    		agentid: {type: 3, value: agentid}, 
			    		otheragent: {type: 1, value: otheragent}
			    	}, 'queryagentstate');
			    }
			    
			    softphone.getcurrentagent = function(dn, otheragentid, options) {
			    	//REQ_GETCURRENTAGENT = 118
			    	var req = {request: {type: 1, value: 118}, dn: {type: 3, value: dn}};
			    	if (otheragentid) {
			    		req.OtherAgent = {type: 3, value: otheragentid};
			    	}
			    	return softphone.websocketsend(req, 'getcurrentagent', options);
			    }

				softphone.InternalOnError = function(errMessage, errorCode, errorName)
				{
					var ret = {};
					ret.event = {type: 1, value: $CTI_CONST.CTI_MSG.EVT_ERROR};
		        	ret.dn = {type: 3, value: this.dn};
		        	//ret.channelid = this.channelid;
		        	if (!errorCode) {
		        		errorCode = 80001
		        	}
		        	ret.errorcode = {type: 3, value: errorCode};
		        	ret.errordesc = {type: 3, value: errMessage};
		        	if (errorName) {
		        		ret.errorname = {type: 3, value: errorName};
		        	}
		        	softphone.onMessage(JSON.stringify(ret));
				}

				softphone.websocketsend = function(jsonobj, method, options) {
			    	softphone.ctirefid++;
			    	jsonobj.CTIRefID = {type: 3, value: softphone.ctirefid};
			    	var request = JSON.stringify(jsonobj)
			    	//this.websocket.send(request);
			    	//this.OnSendMessage(request);
			    	
			    	if (options) {
					    var timeout = options.timeout || 30000;
					    //var succevents = options.succevents;
					    //var failevents = options.failevents;
			            var promise = new Promise(function (resolve, reject) {
			                // 向请求队列中添加对象
			                softphone.rqqueue[softphone.ctirefid.toString()] = {
			                    // 超时检测定时器
			                    timer: null,
			                	method : method,
			                	msg: request,
			                	//succevents: succevents,
			                	//failevents: failevents,
			                	options: options,
			                    resolve: resolve,
			                    reject: reject
			                };
			                softphone.checkTimedOut(softphone.ctirefid, timeout);

			                softphone.logmsg("Begin send request:" + request);
			                softphone.websocket.send(request);
						    softphone.logmsg("msg sent");
						    softphone.OnSendMessage(request);
			            });
			            return promise;			
			    	} else {
		                softphone.logmsg("Begin send request:" + request);
		                softphone.websocket.send(request);
					    softphone.logmsg("msg sent");
					    softphone.OnSendMessage(request);
			    	}
			    }
			    
				softphone.checkTimedOut = function (ctirefid, timeout) {
		            var invoke = softphone.rqqueue[ctirefid];
		            if (invoke) {
			            invoke.timer = window.setTimeout(function () {
			                softphone.logmsg("timeout - " + invoke.msg);
			                // 发送超时消息
			                var error = new Error(Error.INVOKE_TIMEOUT, {
			                    method: invoke.method
			                });
			                if (invoke.reject) {
				                invoke.reject(error);
			                } else {
						    	softphone.InternalOnError(error.message, error.code, error.name);
			                }
			                // 删除请求队列中的对象
			                delete softphone.rqqueue[ctirefid];
			            }, timeout);
		            }
		        }

		        softphone.stopCheckTimedOut = function (ctirefid) {
		            var invoke = softphone.rqqueue[ctirefid];
		            if (invoke && invoke.timer) {
		                window.clearTimeout(invoke.timer);
		                invoke.timer = 0;
		            }
		            delete softphone.rqqueue[ctirefid];
		        }
				
				softphone.logmsg = function(msg)
				{
					console.log("[softphone_wscti]"+msg);
				}
				
				adduserdata = function(userdatas, key, type, value) {
			    	if(!userdatas) {
			    		userdatas = JSON.stringify({type : 5, value : {}});
			    	}
			    	if (typeof(userdatas)=='string') {
			    		try {
					    	var t_data = JSON.parse(userdatas);
					    	t_data[key] = {
			    				type : type,
			    				value : value
			    			}
					    	return JSON.stringify(t_data);
			    		} catch (err) {
			    			
			    		}
			    	} else {
			    		userdatas[key] = {
		    				type : type,
		    				value : value
			    		}
			    		return userdatas;
			    	}
			    }
			    
			    userdata2jsonuserdata = function(userdatas) {
			    	//userdatas: JSON Object, JSON string, '|' and '=' splitted key-value string
			    	if (userdatas) {
			    		if (typeof(userdatas) == 'object') {
			    			var ud = {};
			    			for (var v in userdatas) {
			    				if (typeof(userdatas[v])!='object') {
			    					ud[v] = {type: 3, value: userdatas[v]};
			    				} else {
			    					ud[v] = userdatas[v];
			    				}
			    			}
			    			return ud;
			    		}
				    	try{
				    		var t_datas = JSON.parse(userdatas);
					    	return userdatas;
				    	} catch(err) {
			    			var t_data1 = userdatas.split("\|");
			    			var t_data = {};
			    			//for (var onedata in t_data1){
			    			for (var i=0; i < t_data1.length; i++) {
			    				var onedata = t_data1[i];
			    				var n = onedata.indexOf("=");
			    				if (n >= 0) {
			    					t_data[onedata.substr(0, n)] = {"value" : onedata.substr(n+1), "type" : 3};
			    				}
			    			}
			    			//return JSON.stringify(t_data);
			    			return t_data;
				    	}
			    	}
			    }

			    checkuudata = function(userdatas) {
			    	try {
			    		var uud = userdatas['uu_data'];
			    		var uuds = '';
			    		if (!uud) {
			    			uud = userdatas['raw_data'];
			    		}
			    		if (!uud) {
			    			return userdatas;
			    		} else {
			    			var uudo;
			    			var uuds = '';
			    			if (typeof(uud) == 'object') {
			    				if (uud.hasOwnProperty('value')) {
			    					uud = uud.value;
			    				}
			    			}
			    			if (typeof(uud) == 'object') {
			    				uudo = uud;
			    			}
			    			else {
			    				try {
			    					uudo = JSON.parse(uud);
			    				} catch (err) {
			    					return userdatas;
			    				}
			    			}
			    			for (var v in uudo) {
			    				uuds = uuds + '|' + v + keyvaluesplit + uudo[v]; 
			    			}
			    			uuds = uuds.substr(1);
			    			userdatas.uu_data = {type: 3, value: uuds};
			    			return userdatas;
			    		}
			    	} catch (err) {
			    		return userdatas;
			    	}
			    }
			    
			    getuserdatabykey = function(userdatas, key) {
			    	if (!userdatas) {
			    		return '';
			    	}
			    	if (typeof(userdatas=='object')) {
			    		if (userdatas[key]) {
			    			return userdatas[key].value;
			    		} else {
			    			return '';
			    		}
			    	}
			    	try {
				    	var t_data = JSON.parse(userdatas);
				    	if (t_data) {
				    		return t_data[key].value;
				    	}
			    	} catch (err) {
			    		
			    	}
			    }
			    
			    removeuserdatabykey = function(userdatas, key) {
			    	if (typeof(userdatas) == 'object') {
			    		delete userdatas[key];
			    		return JSON.stringify(userdatas);
			    	}
			    	try {
				    	var t_data = JSON.parse(userdatas);
				    	if (t_data) {
				    		if (t_data[key]) {
				    			delete t_data[key];
				    		}
				    		return JSON.stringify(t_data);
				    	}
				    } catch (err) {
				    	
				    }
			    }

			    _onmessage = function(evt) {
			    	console.log("receive: " + evt.data);
			    	var internaluse = false;
	                var datas = JSON.parse(evt.data);
	                var refid = datas.ctirefid;
	                if (refid) {
	                	refid = refid.value;
	          
                        var invoke = softphone.rqqueue[refid];
                        if (invoke) {
                            // 清除超时检测定时器
                            softphone.stopCheckTimedOut(refid);
                            if (invoke.options) {
                            	internaluse = invoke.options.internaluse;
                            }
                            if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_ERROR) {
    			                var error = new Error(Error.REQUEST_FAIL_CTIMSG, {
    			                    method: invoke.method,
    			                    errorcode: datas.errorcode.value,
    			                    data: evt.data
    			                });
    			                if (invoke.reject) {
    				                invoke.reject(error);
    			                } else {
    						    	softphone.InternalOnError(error.message, error.code, error.name);
    			                }
    			            } else {
                				invoke.resolve(datas);
                            }
                        }
	                };
	                for (vinv in softphone.rqqueue) {
	                	var invoke = softphone.rqqueue[vinv];
	                	if (invoke.options && invoke.options.succevents) {
	                		for (var i = 0; i < invoke.options.succevents.length; i++) {
	                			if (invoke.options.succevents[i] == datas.event.value) {
	                				softphone.stopCheckTimedOut(vinv);
	                				invoke.resolve(datas);
	                			}
	                		}
	                	}
	                	if (invoke.options && invoke.options.failevents) {
	                		for (var i = 0; i < invoke.options.failevents.length; i++) {
	                			if (invoke.options.failevents[i] == datas.event.value) {
	                				softphone.stopCheckTimedOut(vinv);
	    			                var error = new Error(Error.REQUEST_FAIL_CTIMSG, {
	    			                    method: invoke.method,
	    			                    errorcode: datas.event.value,
	    			                    datas: datas
	    			                });
	    			                if (invoke.reject) {
	    				                invoke.reject(error);
	    			                } else {
	    						    	softphone.InternalOnError(error.message, error.code, error.name);
	    			                }
	                			}
	                		}
	                	}
	                }
	                
	                switch(parseInt(datas.event.value)){  
	                    case $CTI_CONST.CTI_MSG.EVT_RINGING:		//1
	                    	try {
		                    	if (datas.userdata && datas.uui) {
		                    		var t_userdata = datas.userdata;
	                    			var t_uui = datas.uui.value;
	                    			var t_uui_ar = t_uui.split("\|");
	                    			for (var i=0; i<t_uui_ar.length; i++) {
	                    				var t_uui_1 = t_uui_ar[i].split("=");
	                    				if (t_uui_1.length==2) {
		                    				t_userdata = adduserdata(t_userdata, t_uui_1[0], 3, t_uui_1[1]);
	                    				} 
	                    			}
		                    		datas.userdata = t_userdata;
		                    	}
	                    		
	                    	} catch (err) {
	                    		//
	                    	}
	                    case $CTI_CONST.CTI_MSG.EVT_DIALING:		//20
	                    case $CTI_CONST.CTI_MSG.EVT_ESTABLISH:		//2
	                    case $CTI_CONST.CTI_MSG.EVT_HELD:			//6
	                    case $CTI_CONST.CTI_MSG.EVT_RETRIEVED:		//7
	                    case $CTI_CONST.CTI_MSG.EVT_RELEASED:
	                    case $CTI_CONST.CTI_MSG.EVT_RINGBACK:
	                    case $CTI_CONST.CTI_MSG.EVT_NETWORKREACHED:
	                    	if (!m_Calllist) {
	                    		m_Calllist = {};
	                    	}

	            			var conn = '',
	            				conn1 = '';

	            			if (datas.connectionid) {
	            				conn = datas.connectionid.value;
	            			} else if (datas.callid) {
	            				conn = datas.callid.value;
	            			}
	            			
	            			if (!conn) {
	            				return;
	            			}
	            			if (datas.prevconnectionid) {
	            				conn1 = datas.prevconnectionid.value;
	            			}

	            			if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RELEASED) {
	            				delete m_Calllist[conn];
	            				if (conn1) {
	            					if (m_Calllist[conn1]) {
	            						m_Calllist[conn1].prevconnectionid = '';
	            					}
	            				}
	            			} else {
	            				m_Calllist[conn] = datas;
	            				if (conn1) {
	            					if (m_Calllist[conn1]) {
	            						m_Calllist[conn1].prevconnectionid = conn;
	            					}
	            				}
	            			}
            				
	        				if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_DIALING) {
	        					if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
	        						if (f_autocomplete == 'completetransferwhendialing') {
	        							f_autocomplete = '';
	        							softphone.completetransfer(conn, conn1);
	        						} else if (f_autocomplete == 'completeconferencewhendialing') {
	        							f_autocomplete = '';
	        							softphone.completeconference(conn, conn1);
	        						}
	        					}
	        				} else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_NETWORKREACHED) {
	        					if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
	        						if ((f_autocomplete == 'completetransferwhendialing')||(f_autocomplete == 'completetransferwhennr')) {
	        							f_autocomplete = '';
	        							softphone.completetransfer(conn, conn1);
	        						} else if ((f_autocomplete == 'completeconferencewhendialing')||(f_autocomplete == 'completeconferencewhennr')) {
	        							f_autocomplete = '';
	        							softphone.completeconference(conn, conn1);
	        						}

	        					}
	        				} else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RINGBACK) {
	        					if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
	        						if ((f_autocomplete == 'completetransferwhendialing')||(f_autocomplete == 'completetransferwhennr')||(f_autocomplete == 'completetransferwhenrb')) {
	        							f_autocomplete = '';
	        							softphone.completetransfer(conn, conn1);
	        						} else if ((f_autocomplete == 'completeconferencewhendialing')||(f_autocomplete == 'completeconferencewhennr')||(f_autocomplete == 'completeconferencewhenrb')) {
	        							f_autocomplete = '';
	        							softphone.completeconference(conn, conn1);
	        						}

	        					}
	        				} else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_ESTABLISH) {
	        					if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
	        						if ((f_autocomplete == 'completetransferwhendialing')||(f_autocomplete == 'completetransferwhennr')||(f_autocomplete == 'completetransferwhenrb')||(f_autocomplete == 'completetransferwhenestablish')) {
	        							f_autocomplete = '';
	        							softphone.completetransfer(conn, conn1);
	        						} else if ((f_autocomplete == 'completeconferencewhendialing')||(f_autocomplete == 'completeconferencewhennr')||(f_autocomplete == 'completeconferencewhenrb')||(f_autocomplete == 'completeconferencewhenestablish')) {
	        							f_autocomplete = '';
	        							softphone.completeconference(conn, conn1);
	        						}

	        					}
	        				}

	            			break;
	                    case $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT:
	                    	if (internaluse) {
	                    		evt.data2 = {internaluse: true};
	                    	} else {
	    						console.log('_softphone: websocket.close()');
		                    	softphone.websocket.close();
	                    	}
	                    	break;
	                    case $CTI_CONST.CTI_MSG.EVT_REGISTERED:
	                    	softphone.registereddn = datas.thisdn;
	                    	//debugger;
	                    	break;
	                    case $CTI_CONST.CTI_MSG.EVT_UNREGISTERED:
	                    	softphone.registereddn = '';
	                    	break;
	                    case $CTI_CONST.CTI_MSG.EVT_ERROR:
                    		if (internaluse) {
                    			evt.data2 = {internaluse: true};
                    		} else {
		                    	if (datas.errorcode && !datas.errordesc) {
		                    	    switch (parseInt(datas.errorcode.value)) {
			                    		case 12:	//INVALID_CSTA_DEVICE_IDENTIFIER = 12,
			                    			datas.errordesc = {type: 3, value: '无效的分机号码：' + datas.thisdn.value};
			                    			evt.data2 = JSON.stringify(datas);
			                    			break;
			                    		case 1:		//GENERIC_OPERATION = 1,
			                    			datas.errordesc = {type: 3, value: '错误码：' + datas.errorcode.value + '，可能是分机未注册。'};
			                    			evt.data2 = JSON.stringify(datas);
			                    			break;
		                    		}
	                    			
	                    		}
		                	}
	                    //	break;
	                }
	                
			    }
			    
			    return softphone;
			}
		};
	
	return ELITEWSCTIClient.createNew();
	
});
